{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a77a2d11",
   "metadata": {},
   "source": [
    "    This tutorial is to get familiar with the GRAND's Coordinate system written in Python. GRAND's coordinate system is developed for the GRAND collaboration and it does not depend on astropy. This tutorial shows a step-by-step process to use them.\n",
    "\n",
    "    Four coordinate systems (CS) are defined, i.e. ECEF, Geodetic, LTP and GRANDCS. GRANDCS is a subclass of LTP. More coordinate systems, including celestial coordinate systems, and their transformation will be added in future. Defining a coordinate in a required CS is done by instantiating the CS. For example, to define an ECEF or Geodetic CS at the point where equator intersects prime-meridian is done simply by:\n",
    "    \n",
    "        ecef     = ECEF(x=6378137, y=0, z=0)\n",
    "        geodetic = Geodetic(latitude=0, longitude=0, height=0)\n",
    "        \n",
    "    Similarly, to define an origin of GRANDCS is done by:\n",
    "    \n",
    "        grandcs  = GRANDCS(x=0, y=0, z=0)\n",
    "    \n",
    "    These CS can be transformed among themselves by two easy-to-use methods:\n",
    "    \n",
    "        1. Instantiating a required CS with a given CS as an input\n",
    "            \n",
    "            ecef1     = ECEF(geodetic)    --> changing from Geodetic CS to ECEF CS.\n",
    "            ecef2     = ECEF(grandcs)     --> changing from GRAND CS to ECEF CS.\n",
    "            \n",
    "            geodetic1 = Geodetic(ecef)    --> changing from ECEF CS to Geodetic CS.\n",
    "            geodetic2 = Geodetic(grandcs) --> changing from GRAND CS to Geodetic CS.\n",
    "            \n",
    "            grandcs1  = GRANDCS(ecef)     --> changing from ECEF CS to GRANDCS.\n",
    "            grandcs1  = GRANDCS(geodetic) --> changing from Geodetic CS to GRANDCS.\n",
    "            \n",
    "        2. Calling a method from the given CS object.\n",
    "            \n",
    "            ecef1     = geodetic.geodetic_to_ecef()\n",
    "            ecef2     = grandcs.grand_to_ecef()\n",
    "            \n",
    "            geodetic1 = ecef.ecef_to_geodetic()\n",
    "            geodetic2 = grandcs.grand_to_geodetic()\n",
    "            \n",
    "            grandcs1  = ecef.ecef_to_grand()\n",
    "            grandcs2  = geodetic.geodetic_to_grand()\n",
    "\n",
    "\n",
    "    GRAND coordinate system requires you to define a local tangential plane (LTP) with given orientation (ENU, NWU etc). GRAND's x-axis points toward the local magnetic North. Y-axis is 90 degree West from the magnetic North. To know the local magnetic North, we must know the declination angle at a given location and observation time (obstime). 'geomagnetic' module is written to calculate local magnetic field and declination angle at a given time and location using some geomagnetic model.\n",
    "\n",
    "    Using 'geomagnetic' module, magnetic field can be defined in two different ways (see below) depending on the input location. Default geomagnetic model ('IGRF13) and default obstime ('2020-01-01') is used if not given.\n",
    "        \n",
    "        1. Location can be given as ECEF, Geodetic, or GRAND coordinate system. 'x' below can be in ECEF, Geodetic, or GRAND CS.\n",
    "        \n",
    "            gm = Geomagnet(location=x)    \n",
    "            gm = Geomagnet(location=x, model='IGRF13', obstime='2021-08-30')\n",
    "            \n",
    "        2. Location can be given as latitude, longitude, and height.\n",
    "        \n",
    "            gm = Geomagnet(latitude=0, longitude=0, height=0)\n",
    "            gm = Geomagnet(latitude=0, longitude=0, height=0, model='IGRF13', obstime='2020-08-30')\n",
    "            \n",
    "    TypeError will occur if location is not provided. 'obstime' is in isoformat ('2020-08-30') or in datetime.date(2020, 8, 30). If obstime is not provided, a default date ('2020-01-01') is used. After the geomagnetic field is instantiated, you can get the required quantity by:\n",
    "    \n",
    "        field       = gm.field          Output: CartesianRepresentation(x=Bx, y=By, z=Bz)\n",
    "        declination = gm.declination    Output: in degree\n",
    "        inclination = gm.inclination    Output: in degree\n",
    "        model       = gm.model          Output: in string\n",
    "        obstime     = gm.obstime        Output: in datetime.date()\n",
    "        location    = gm.location       Output: in Geodetic(latitude=x, longitude=x, height=x)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c1e59c35",
   "metadata": {
    "hideCode": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Welcome to JupyROOT 6.26/02\n"
     ]
    }
   ],
   "source": [
    "# from grand.tools import Coordinates, CartesianRepresentation, SphericalRepresentation, GeodeticRepresentation\n",
    "# from grand.tools import ECEF, Geodetic, GRAND, LTP\n",
    "# from grand.tools import Geomagnet\n",
    "\n",
    "from grand import (\n",
    "    Coordinates,\n",
    "    CartesianRepresentation,\n",
    "    SphericalRepresentation,\n",
    "    GeodeticRepresentation,\n",
    ")\n",
    "from grand import ECEF, Geodetic, GRANDCS, LTP\n",
    "from grand import Geomagnet\n",
    "\n",
    "import numpy as np\n",
    "import datetime\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "params = {\n",
    "    \"legend.fontsize\": 16,\n",
    "    \"axes.labelsize\": 22,\n",
    "    \"axes.titlesize\": 17,\n",
    "    \"xtick.labelsize\": 20,\n",
    "    \"ytick.labelsize\": 20,\n",
    "    \"figure.figsize\": (12, 12),\n",
    "    \"axes.grid\": True,\n",
    "}\n",
    "plt.rcParams.update(params)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "838abd19",
   "metadata": {},
   "source": [
    "    Basic data structure for all coordinate system is a numpy.ndarray. Coordinate data are stored as 3xn ndarray with random entries, where n=number of coordinate points and n>=1 for point and vector/array.\n",
    "        \n",
    "        [[x1], \n",
    "         [y1], \n",
    "         [z1]]\n",
    "         \n",
    "         OR\n",
    "         \n",
    "        [[x1, x2, ..xn], \n",
    "         [y1, y2, ..yn], \n",
    "         [z1, z2, ..zn]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7062c7c5",
   "metadata": {
    "hideCode": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------Basic Data Structure (Random Entries)---------\n",
      "[[0. ]\n",
      " [0.5]\n",
      " [1. ]] <class 'grand.geo.coordinates.Coordinates'> n=1\n",
      "\n",
      "[[6.8367879e-316 0.0000000e+000 0.0000000e+000 0.0000000e+000\n",
      "  0.0000000e+000]\n",
      " [0.0000000e+000 0.0000000e+000 0.0000000e+000 0.0000000e+000\n",
      "  0.0000000e+000]\n",
      " [0.0000000e+000 0.0000000e+000 0.0000000e+000 0.0000000e+000\n",
      "  0.0000000e+000]] <class 'grand.geo.coordinates.Coordinates'> n=5\n",
      "\n",
      "Note that random values are automatically selected to fill the array.\n"
     ]
    }
   ],
   "source": [
    "# Basic data structure.\n",
    "\n",
    "cord1 = Coordinates(1)  # 3x1ndarray with random entries is formed in this example.\n",
    "cord2 = Coordinates(5)  # 3x5 ndarray with random entries is formed in this example.\n",
    "\n",
    "print(\"---------Basic Data Structure (Random Entries)---------\")\n",
    "print(cord1, type(cord1), \"n=1\\n\")\n",
    "print(cord2, type(cord2), \"n=5\\n\")\n",
    "print(\"Note that random values are automatically selected to fill the array.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02bd025c",
   "metadata": {},
   "source": [
    "    Cartesian coordinate system is defined as 'CartesianRepresentation' and has x, y, and z as an input. Other Representation (SphericalRepresentation, ECEF, LTP, GRANDCS) can also be given as an input and will automatically be converted into CartesianRepresentation. ECEF, LTP and GRANDCS are based on CartesianRepresentation. Similarly, spherical coordinate system is defined by 'SphericalRepresentation' and has similar features like CartesianRepresentation. theta, phi, and r are inputs of SphericalRepresentation.\n",
    "        \n",
    "        cartesian = CartesianRepresentation(x=0, y=0, z=0)\n",
    "        spherical = SphericalRepresentation(theta=0, phi=0, r=0)\n",
    "        \n",
    "    These representations can be transformed among themselves by two easy-to-use methods:\n",
    "    \n",
    "        1. Instantiating a required representation with a given representation as an input\n",
    "            \n",
    "            cartesian1 = CartesianRepresentation(spherical)  --> changing from spherical to cartesian.\n",
    "            spherical1 = SphericalRepresentation(cartesian)  --> changing from cartesian to spherical.\n",
    "            \n",
    "        2. Calling a method from the given representation object.\n",
    "            \n",
    "            cartesian1 = spherical.spherical_to_cartesian()\n",
    "            spherical1 = cartesian.cartesian_to_spherical()\n",
    "            \n",
    "            \n",
    "    These representations also have getter and setter method.\n",
    "        \n",
    "    ----Getter\n",
    "        x = cartesian.x\n",
    "        y = cartesian.y\n",
    "        z = cartesian.z\n",
    "        \n",
    "    ----Setter\n",
    "        cartesian.x = x*x\n",
    "        cartesian.y = y*y\n",
    "        cartesian.z = z*z\n",
    "        \n",
    "    Similar methods for SphericalRepresentation but use theta, phi, and r instead of x, y, and z."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "90e41b4c",
   "metadata": {
    "hideCode": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------Cartesian Representation--------\n",
      "\n",
      "-- 3x1 array. n=1\n",
      "[[1.]\n",
      " [2.]\n",
      " [3.]] <class 'grand.geo.coordinates.CartesianRepresentation'> Initial\n",
      "--getter\n",
      "[1.] X <class 'grand.geo.coordinates.CartesianRepresentation'> getter\n",
      "[2.] Y <class 'grand.geo.coordinates.CartesianRepresentation'> getter\n",
      "[3.] Z <class 'grand.geo.coordinates.CartesianRepresentation'> getter\n",
      "--setter\n",
      "[[1.]\n",
      " [4.]\n",
      " [9.]] <class 'grand.geo.coordinates.CartesianRepresentation'> setter (squared)\n",
      "--Cartesian to Spherical (theta, phi, r)\n",
      "[[24.61359765]\n",
      " [75.96375653]\n",
      " [ 9.89949494]] <class 'grand.geo.coordinates.SphericalRepresentation'> style 1\n",
      "[[24.61359765]\n",
      " [75.96375653]\n",
      " [ 9.89949494]] <class 'grand.geo.coordinates.SphericalRepresentation'> style 2\n",
      "\n",
      "-- 3x5 array. n=5\n",
      "[[1. 1. 1. 1. 1.]\n",
      " [2. 2. 2. 2. 2.]\n",
      " [3. 3. 3. 3. 3.]] <class 'grand.geo.coordinates.CartesianRepresentation'> Initial\n",
      "--getter\n",
      "[1. 1. 1. 1. 1.] X <class 'grand.geo.coordinates.CartesianRepresentation'> getter\n",
      "[2. 2. 2. 2. 2.] Y <class 'grand.geo.coordinates.CartesianRepresentation'> getter\n",
      "[3. 3. 3. 3. 3.] Z <class 'grand.geo.coordinates.CartesianRepresentation'> getter\n",
      "--setter\n",
      "[[1. 1. 1. 1. 1.]\n",
      " [4. 4. 4. 4. 4.]\n",
      " [9. 9. 9. 9. 9.]] <class 'grand.geo.coordinates.CartesianRepresentation'> setter (squared)\n",
      "--Cartesian to Spherical (theta, phi, r)\n",
      "[[24.61359765 24.61359765 24.61359765 24.61359765 24.61359765]\n",
      " [75.96375653 75.96375653 75.96375653 75.96375653 75.96375653]\n",
      " [ 9.89949494  9.89949494  9.89949494  9.89949494  9.89949494]] <class 'grand.geo.coordinates.SphericalRepresentation'> style 1\n",
      "[[24.61359765 24.61359765 24.61359765 24.61359765 24.61359765]\n",
      " [75.96375653 75.96375653 75.96375653 75.96375653 75.96375653]\n",
      " [ 9.89949494  9.89949494  9.89949494  9.89949494  9.89949494]] <class 'grand.geo.coordinates.SphericalRepresentation'> style 2\n"
     ]
    }
   ],
   "source": [
    "print(\"---------Cartesian Representation--------\")\n",
    "x = np.ones(5)  # [1. 1. 1. 1. 1.]\n",
    "y = 1 + x  # [2. 2. 2. 2. 2.]\n",
    "z = 1 + y  # [3. 3. 3. 3. 3.]\n",
    "\n",
    "# forms 3xn ndarray ([[x1, x2, ..xn], [y1, y2, ..yn], [z1, z2, ..zn]], n=len(x))\n",
    "cart1 = CartesianRepresentation(x=1, y=2, z=3)\n",
    "cart2 = CartesianRepresentation(x=x, y=y, z=z)\n",
    "\n",
    "print(\"\\n-- 3x1 array. n=1\")\n",
    "print(cart1, type(cart1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(cart1.x, \"X\", type(cart1), \"getter\")\n",
    "print(cart1.y, \"Y\", type(cart1), \"getter\")\n",
    "print(cart1.z, \"Z\", type(cart1), \"getter\")\n",
    "\n",
    "cart1.x = cart1.x ** 2\n",
    "cart1.y = cart1.y ** 2\n",
    "cart1.z = cart1.z ** 2\n",
    "print(\"--setter\")\n",
    "print(cart1, type(cart1), \"setter (squared)\")\n",
    "\n",
    "cts1a = cart1.cartesian_to_spherical()\n",
    "cts1b = SphericalRepresentation(cart1)\n",
    "print(\"--Cartesian to Spherical (theta, phi, r)\")\n",
    "print(cts1a, type(cts1a), \"style 1\")\n",
    "print(cts1b, type(cts1b), \"style 2\")\n",
    "\n",
    "print(\"\\n-- 3x5 array. n=5\")\n",
    "print(cart2, type(cart2), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(cart2.x, \"X\", type(cart2), \"getter\")\n",
    "print(cart2.y, \"Y\", type(cart2), \"getter\")\n",
    "print(cart2.z, \"Z\", type(cart2), \"getter\")\n",
    "\n",
    "cart2.x = x * x\n",
    "cart2.y = y * y\n",
    "cart2.z = z * z\n",
    "print(\"--setter\")\n",
    "print(cart2, type(cart2), \"setter (squared)\")\n",
    "cts2a = cart2.cartesian_to_spherical()\n",
    "cts2b = SphericalRepresentation(cart2)\n",
    "print(\"--Cartesian to Spherical (theta, phi, r)\")\n",
    "print(cts2a, type(cts2a), \"style 1\")\n",
    "print(cts2b, type(cts2b), \"style 2\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1e515ef8",
   "metadata": {
    "hideCode": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------Spherical Representation--------\n",
      "\n",
      "-- 3x1 array. n=1\n",
      "[[1.]\n",
      " [2.]\n",
      " [3.]] <class 'grand.geo.coordinates.SphericalRepresentation'> Initial\n",
      "--getter\n",
      "[1.] theta <class 'grand.geo.coordinates.SphericalRepresentation'> getter\n",
      "[2.] phi <class 'grand.geo.coordinates.SphericalRepresentation'> getter\n",
      "[3.] r <class 'grand.geo.coordinates.SphericalRepresentation'> getter\n",
      "--setter\n",
      "[[1.]\n",
      " [4.]\n",
      " [9.]] <class 'grand.geo.coordinates.SphericalRepresentation'> setter (squared)\n",
      "--Spherical to Cartesian (x, y, z)\n",
      "[[0.15668904]\n",
      " [0.01095676]\n",
      " [8.99862926]] <class 'grand.geo.coordinates.CartesianRepresentation'> style 1\n",
      "[[0.15668904]\n",
      " [0.01095676]\n",
      " [8.99862926]] <class 'grand.geo.coordinates.CartesianRepresentation'> style 2\n",
      "\n",
      "-- 3x5 array. n=5\n",
      "[[1. 1. 1. 1. 1.]\n",
      " [2. 2. 2. 2. 2.]\n",
      " [3. 3. 3. 3. 3.]] <class 'grand.geo.coordinates.SphericalRepresentation'> Initial\n",
      "--getter\n",
      "[1. 1. 1. 1. 1.] theta <class 'grand.geo.coordinates.SphericalRepresentation'> getter\n",
      "[2. 2. 2. 2. 2.] phi <class 'grand.geo.coordinates.SphericalRepresentation'> getter\n",
      "[3. 3. 3. 3. 3.] r <class 'grand.geo.coordinates.SphericalRepresentation'> getter\n",
      "--setter\n",
      "[[1. 1. 1. 1. 1.]\n",
      " [4. 4. 4. 4. 4.]\n",
      " [9. 9. 9. 9. 9.]] <class 'grand.geo.coordinates.SphericalRepresentation'> setter (squared)\n",
      "--Spherical to Cartesian (x, y, z)\n",
      "[[0.15668904 0.15668904 0.15668904 0.15668904 0.15668904]\n",
      " [0.01095676 0.01095676 0.01095676 0.01095676 0.01095676]\n",
      " [8.99862926 8.99862926 8.99862926 8.99862926 8.99862926]] <class 'grand.geo.coordinates.CartesianRepresentation'> style 1\n",
      "[[0.15668904 0.15668904 0.15668904 0.15668904 0.15668904]\n",
      " [0.01095676 0.01095676 0.01095676 0.01095676 0.01095676]\n",
      " [8.99862926 8.99862926 8.99862926 8.99862926 8.99862926]] <class 'grand.geo.coordinates.CartesianRepresentation'> style 2\n"
     ]
    }
   ],
   "source": [
    "print(\"---------Spherical Representation--------\")\n",
    "\n",
    "t = np.ones(5)  # theta=1 degree\n",
    "p = 1 + t  # phi=2 degree\n",
    "r = 1 + p  # r=3 m\n",
    "\n",
    "sphr1 = SphericalRepresentation(theta=1, phi=2, r=3)\n",
    "sphr2 = SphericalRepresentation(theta=t, phi=p, r=r)\n",
    "\n",
    "print(\"\\n-- 3x1 array. n=1\")\n",
    "print(sphr1, type(sphr1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(sphr1.theta, \"theta\", type(sphr1.theta), \"getter\")\n",
    "print(sphr1.phi, \"phi\", type(sphr1.phi), \"getter\")\n",
    "print(sphr1.r, \"r\", type(sphr1.r), \"getter\")\n",
    "\n",
    "sphr1.theta = sphr1.theta ** 2\n",
    "sphr1.phi = sphr1.phi ** 2\n",
    "sphr1.r = sphr1.r ** 2\n",
    "print(\"--setter\")\n",
    "print(sphr1, type(sphr1), \"setter (squared)\")\n",
    "\n",
    "print(\"--Spherical to Cartesian (x, y, z)\")\n",
    "stc1a = sphr1.spherical_to_cartesian()\n",
    "stc1b = CartesianRepresentation(sphr1)\n",
    "print(stc1a, type(stc1a), \"style 1\")\n",
    "print(stc1b, type(stc1b), \"style 2\")\n",
    "\n",
    "print(\"\\n-- 3x5 array. n=5\")\n",
    "print(sphr2, type(sphr2), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(sphr2.theta, \"theta\", type(sphr2.theta), \"getter\")\n",
    "print(sphr2.phi, \"phi\", type(sphr2.phi), \"getter\")\n",
    "print(sphr2.r, \"r\", type(sphr2.r), \"getter\")\n",
    "\n",
    "sphr2.theta = sphr2.theta ** 2\n",
    "sphr2.phi = sphr2.phi ** 2\n",
    "sphr2.r = sphr2.r ** 2\n",
    "print(\"--setter\")\n",
    "print(sphr2, type(sphr2), \"setter (squared)\")\n",
    "\n",
    "print(\"--Spherical to Cartesian (x, y, z)\")\n",
    "stc2a = sphr2.spherical_to_cartesian()\n",
    "stc2b = CartesianRepresentation(sphr2)\n",
    "print(stc2a, type(stc2a), \"style 1\")\n",
    "print(stc2b, type(stc2b), \"style 2\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6bcdcb3",
   "metadata": {
    "hideCode": false
   },
   "source": [
    "    Geodetic representation is defined as 'GeodeticRepresentation' and has latitude, longitude, and height as inputs. Geodetic coordinate system is based on GeodeticRepresentation.\n",
    "\n",
    "        geodetic = GeodeticRepresentation(latitude=0, longitude=0, height=0)\n",
    "    \n",
    "    This representation have getter and setter method.\n",
    "\n",
    "    ----Getter\n",
    "        lat = geodetic.latitude\n",
    "        lon = geodetic.longitude\n",
    "        het = geodetic.height\n",
    "\n",
    "    ----Setter\n",
    "        geodetic.latitude  = lat*lat\n",
    "        geodetic.longitude = lon*lon\n",
    "        geodetic.height    = het*het\n",
    "        \n",
    "    Note that there is no conversion from GeodeticRepresentation to CartesianRepresentaiton and SphericalRepresentation because geodetic has a fixed axes whereas cartesian and spherical do not."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "87c73b11",
   "metadata": {
    "hideCode": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------Geodetic Representation--------\n",
      "\n",
      "-- 3x1 array. n=1\n",
      "[[0.]\n",
      " [0.]\n",
      " [2.]] <class 'grand.geo.coordinates.GeodeticRepresentation'> Initial\n",
      "--getter\n",
      "[0.] latitude [deg]  <class 'grand.geo.coordinates.GeodeticRepresentation'> getter\n",
      "[0.] longitude [deg] <class 'grand.geo.coordinates.GeodeticRepresentation'> getter\n",
      "[2.] height [m]      <class 'grand.geo.coordinates.GeodeticRepresentation'> getter\n",
      "--setter\n",
      "[[0.]\n",
      " [0.]\n",
      " [4.]] <class 'grand.geo.coordinates.GeodeticRepresentation'> setter (squared)\n",
      "\n",
      "--3x4 array. n=4\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [2. 2. 2. 2.]] <class 'grand.geo.coordinates.GeodeticRepresentation'> Initial\n",
      "--getter\n",
      "[0. 0. 0. 0.] latitude [deg]  <class 'grand.geo.coordinates.GeodeticRepresentation'> getter\n",
      "[0. 0. 0. 0.] longitude [deg] <class 'grand.geo.coordinates.GeodeticRepresentation'> getter\n",
      "[2. 2. 2. 2.] height [m]      <class 'grand.geo.coordinates.GeodeticRepresentation'> getter\n",
      "--setter\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [4. 4. 4. 4.]] <class 'grand.geo.coordinates.GeodeticRepresentation'> setter (squared)\n"
     ]
    }
   ],
   "source": [
    "print(\"---------Geodetic Representation--------\")\n",
    "lat = np.zeros(4)\n",
    "lon = np.zeros(4)\n",
    "height = 2 * np.ones(4)  # 2 m above mean sea level at lat=0, lon=0.\n",
    "geod1 = GeodeticRepresentation(latitude=0, longitude=0, height=2)\n",
    "geod2 = GeodeticRepresentation(latitude=lat, longitude=lon, height=height)\n",
    "\n",
    "print(\"\\n-- 3x1 array. n=1\")\n",
    "print(geod1, type(geod1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(geod1.latitude, \"latitude [deg] \", type(geod1.latitude), \"getter\")\n",
    "print(geod1.longitude, \"longitude [deg]\", type(geod1.longitude), \"getter\")\n",
    "print(geod1.height, \"height [m]     \", type(geod1.height), \"getter\")\n",
    "\n",
    "geod1.latitude = geod1.latitude ** 2\n",
    "geod1.longitude = geod1.longitude ** 2\n",
    "geod1.height = geod1.height ** 2\n",
    "print(\"--setter\")\n",
    "print(geod1, type(geod1), \"setter (squared)\")\n",
    "\n",
    "print(\"\\n--3x4 array. n=4\")\n",
    "print(geod2, type(geod2), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(geod2.latitude, \"latitude [deg] \", type(geod2.latitude), \"getter\")\n",
    "print(geod2.longitude, \"longitude [deg]\", type(geod2.longitude), \"getter\")\n",
    "print(geod2.height, \"height [m]     \", type(geod2.height), \"getter\")\n",
    "\n",
    "geod2.latitude = geod2.latitude ** 2\n",
    "geod2.longitude = geod2.longitude ** 2\n",
    "geod2.height = geod2.height ** 2\n",
    "print(\"--setter\")\n",
    "print(geod2, type(geod2), \"setter (squared)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91a29d41",
   "metadata": {},
   "source": [
    "    ----------- Geodetic Coordinate System ----------------\n",
    "    \n",
    "    Generic container for Geodetic coordinate system. Center of this frame is the center of Earth.\n",
    "\n",
    "\tLatitude: Angle north and south of the equator. +ve in the northern hemisphere, \n",
    "\t\t\t  -ve in the southern hemisphere. Range: -90 deg (South Pole) \n",
    "\t\t\t  to +90 deg (North Pole). In equator, latitude = 0.\n",
    "\tLongitude: Angle east and west of the Prime Meridian. The Prime Meridian \n",
    "\t\t\t   is a north-south line that passes through Greenwich, UK. \n",
    "\t\t\t   +ve to the east of the Prime Meridian, -ve to the west. \n",
    "\t\t\t   Range: -180 deg to +180 deg.\n",
    "\tHeight:\tAlso called altitude or elevation, this represents the height above \n",
    "\t\t\tthe Earth ellipsoid, measured in meters. The Earth ellipsoid is a \n",
    "\t\t\tmathematical surface defined by a semi-major axis and a semi-minor axis. \n",
    "\t\t\tThe most common values for these two parameters are defined by \n",
    "\t\t\tthe World Geodetic Standard 1984 (WGS-84). The WGS-84 ellipsoid is \n",
    "\t\t\tintended to correspond to mean sea level. A Geodetic height of zero \n",
    "\t\t\ttherefore roughly corresponds to sea level, with positive values increasing \n",
    "\t\t\taway from the Earth’s center. The theoretical range of height values is \n",
    "\t\t\tfrom the center of the Earth (about -6,371km) to positive infinity. \n",
    "\n",
    "    This CS is built on top of GeodeticRepresentation and has latitude, longitude, and height as inputs. Latitude, longitude, and height can be either number or numpy.ndarray. It also takes other known coordinate system as an input and automatically convert it into Geodetic CS. It has getter and setter method.\n",
    "\n",
    "    geodetic = Geodetic(latitude=0, longitude=0, height=0)\n",
    "    geodetic = Geodetic(latitude=array, longitude=array, height=array)\n",
    "    geodetic = Geodetic(ecef)\n",
    "    geodetic = Geodetic(grandcs)\n",
    "\n",
    "    ----Getter\n",
    "        lat = geodetic.latitude\n",
    "        lon = geodetic.longitude\n",
    "        het = geodetic.height\n",
    "\n",
    "    ----Setter\n",
    "        geodetic.latitude  = lat*lat\n",
    "        geodetic.longitude = lon*lon\n",
    "        geodetic.height    = het*het\n",
    "        \n",
    "    There are two methods to transform from other known coordinate system to Geodetic CS.\n",
    "    \n",
    "    1. Instantiating a required CS with a given CS as an input\n",
    "    \n",
    "        geodetic1 = Geodetic(ecef)    --> changing from ECEF CS to Geodetic CS.\n",
    "        geodetic2 = Geodetic(grandcs) --> changing from GRAND CS to Geodetic CS.\n",
    "\n",
    "    2. Calling a method from the given CS object.\n",
    "\n",
    "        geodetic1 = ecef.ecef_to_geodetic()\n",
    "        geodetic2 = grandcs.grand_to_geodetic()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a24c9e70",
   "metadata": {
    "hideCode": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----3x1 Geodetic (lat, lon, height array input)\n",
      "[[0.]\n",
      " [0.]\n",
      " [2.]] <class 'grand.geo.coordinates.Geodetic'> Initial\n",
      "--getter\n",
      "[0.] latitude  <class 'grand.geo.coordinates.Geodetic'> getter\n",
      "[0.] longitude <class 'grand.geo.coordinates.Geodetic'> getter\n",
      "[2.] height    <class 'grand.geo.coordinates.Geodetic'> getter\n",
      "--setter\n",
      "[[10.]\n",
      " [10.]\n",
      " [12.]] <class 'grand.geo.coordinates.Geodetic'> setter (added 10) \n",
      "\n",
      "----3x4 Geodetic (lat, lon, height array input)-----\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [2. 2. 2. 2.]] <class 'grand.geo.coordinates.Geodetic'> Initial\n",
      "--getter\n",
      "[0. 0. 0. 0.] latitude  <class 'grand.geo.coordinates.Geodetic'> getter\n",
      "[0. 0. 0. 0.] longitude <class 'grand.geo.coordinates.Geodetic'> getter\n",
      "[2. 2. 2. 2.] height    <class 'grand.geo.coordinates.Geodetic'> getter\n",
      "--setter\n",
      "[[10. 10. 10. 10.]\n",
      " [10. 10. 10. 10.]\n",
      " [12. 12. 12. 12.]] <class 'grand.geo.coordinates.Geodetic'> setter (added 10) \n",
      "\n",
      "\n",
      "----Geodetic to other cs transformation------\n",
      "\n",
      "----3x1 array\n",
      "--to ECEF\n",
      "[[0.]\n",
      " [0.]\n",
      " [2.]] <class 'grand.geo.coordinates.Geodetic'> Initial\n",
      "[[6378156.17734519]\n",
      " [      0.        ]\n",
      " [      0.        ]] <class 'grand.geo.coordinates.ECEF'> style 1\n",
      "[[6378156.17734519]\n",
      " [      0.        ]\n",
      " [      0.        ]] <class 'grand.geo.coordinates.ECEF'> style 2\n",
      "--to GRANDCS\n",
      "[[  118397.6435191 ]\n",
      " [ 6374539.45659599]\n",
      " [-6570656.59324208]] <class 'grand.geo.coordinates.GRANDCS'> style 1\n",
      "[[  118397.6435191 ]\n",
      " [ 6374539.45659599]\n",
      " [-6570656.59324208]] <class 'grand.geo.coordinates.GRANDCS'> style 2\n",
      "\n",
      "----3x4 array\n",
      "--to ECEF\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [2. 2. 2. 2.]] <class 'grand.geo.coordinates.Geodetic'> Initial\n",
      "[[6378156.17734519 6378156.17734519 6378156.17734519 6378156.17734519]\n",
      " [      0.               0.               0.               0.        ]\n",
      " [      0.               0.               0.               0.        ]] <class 'grand.geo.coordinates.ECEF'> style 1\n",
      "[[6378156.17734519 6378156.17734519 6378156.17734519 6378156.17734519]\n",
      " [      0.               0.               0.               0.        ]\n",
      " [      0.               0.               0.               0.        ]] <class 'grand.geo.coordinates.ECEF'> style 2\n",
      "--to GRANDCS\n",
      "[[  118397.6435191    118397.6435191    118397.6435191    118397.6435191 ]\n",
      " [ 6374539.45659599  6374539.45659599  6374539.45659599  6374539.45659599]\n",
      " [-6570656.59324208 -6570656.59324208 -6570656.59324208 -6570656.59324208]] <class 'grand.geo.coordinates.GRANDCS'> style 1\n",
      "[[  118397.6435191    118397.6435191    118397.6435191    118397.6435191 ]\n",
      " [ 6374539.45659599  6374539.45659599  6374539.45659599  6374539.45659599]\n",
      " [-6570656.59324208 -6570656.59324208 -6570656.59324208 -6570656.59324208]] <class 'grand.geo.coordinates.GRANDCS'> style 2\n",
      "\n",
      "----Mathematical Operations (shape should be the same)\n",
      "geodetic1*geodetic1 + 3*geodetic1\n",
      "[[ 0.]\n",
      " [ 0.]\n",
      " [10.]]\n",
      "geodtic2*geodtic2 + 3*geodtic2\n",
      "[[ 0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.]\n",
      " [10. 10. 10. 10.]]\n"
     ]
    }
   ],
   "source": [
    "geodtic1 = Geodetic(latitude=0, longitude=0, height=2)\n",
    "geodtic2 = Geodetic(latitude=lat, longitude=lon, height=height)\n",
    "\n",
    "print(\"----3x1 Geodetic (lat, lon, height array input)\")\n",
    "print(geodtic1, type(geodtic1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(geodtic1.latitude, \"latitude \", type(geodtic1), \"getter\")\n",
    "print(geodtic1.longitude, \"longitude\", type(geodtic1), \"getter\")\n",
    "print(geodtic1.height, \"height   \", type(geodtic1), \"getter\")\n",
    "\n",
    "geodtic1.latitude = geodtic1.latitude + 10\n",
    "geodtic1.longitude = geodtic1.longitude + 10\n",
    "geodtic1.height = geodtic1.height + 10\n",
    "print(\"--setter\")\n",
    "print(geodtic1, type(geodtic1), \"setter (added 10) \\n\")\n",
    "\n",
    "print(\"----3x4 Geodetic (lat, lon, height array input)-----\")\n",
    "print(geodtic2, type(geodtic1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(geodtic2.latitude, \"latitude \", type(geodtic2), \"getter\")\n",
    "print(geodtic2.longitude, \"longitude\", type(geodtic2), \"getter\")\n",
    "print(geodtic2.height, \"height   \", type(geodtic2), \"getter\")\n",
    "\n",
    "geodtic2.latitude = geodtic2.latitude + 10\n",
    "geodtic2.longitude = geodtic2.longitude + 10\n",
    "geodtic2.height = geodtic2.height + 10\n",
    "print(\"--setter\")\n",
    "print(geodtic2, type(geodtic2), \"setter (added 10) \\n\")\n",
    "\n",
    "\n",
    "Ex = 6378139 * np.ones(5)  # 2 m above mean sea level. R_earth_eqr = 6378137 m.\n",
    "Ey = np.zeros(5)\n",
    "Ez = np.zeros(5)\n",
    "ka = np.zeros(5)\n",
    "\n",
    "ecef = ECEF(x=Ex, y=Ey, z=Ez)  # more on this later.\n",
    "grandcs = GRANDCS(x=ka, y=ka, z=ka)  # GRANDCS origin, default obstime. more on this later.\n",
    "geodtic1 = Geodetic(latitude=0, longitude=0, height=2)\n",
    "geodtic2 = Geodetic(latitude=lat, longitude=lon, height=height)\n",
    "\n",
    "print(\"\\n----Geodetic to other cs transformation------\\n\")\n",
    "gte1a = ECEF(geodtic1)\n",
    "gte1b = geodtic1.geodetic_to_ecef()\n",
    "\n",
    "print(\"----3x1 array\")\n",
    "\n",
    "print(\"--to ECEF\")\n",
    "print(geodtic1, type(geodtic1), \"Initial\")\n",
    "print(gte1a, type(gte1a), \"style 1\")\n",
    "print(gte1b, type(gte1b), \"style 2\")\n",
    "\n",
    "print(\"--to GRANDCS\")\n",
    "gtG1a = GRANDCS(geodtic1)\n",
    "gtG1b = geodtic1.geodetic_to_grandcs()\n",
    "print(gtG1a, type(gtG1a), \"style 1\")\n",
    "print(gtG1b, type(gtG1b), \"style 2\")\n",
    "\n",
    "gte2a = ECEF(geodtic2)\n",
    "gte2b = geodtic2.geodetic_to_ecef()\n",
    "\n",
    "print(\"\\n----3x4 array\")\n",
    "\n",
    "print(\"--to ECEF\")\n",
    "print(geodtic2, type(geodtic2), \"Initial\")\n",
    "print(gte2a, type(gte2a), \"style 1\")\n",
    "print(gte2b, type(gte2b), \"style 2\")\n",
    "\n",
    "print(\"--to GRANDCS\")\n",
    "gtG2a = GRANDCS(geodtic2)\n",
    "gtG2b = geodtic2.geodetic_to_grandcs()\n",
    "print(gtG2a, type(gtG2a), \"style 1\")\n",
    "print(gtG2b, type(gtG2b), \"style 2\")\n",
    "\n",
    "print(\"\\n----Mathematical Operations (shape should be the same)\")\n",
    "print(\"geodetic1*geodetic1 + 3*geodetic1\")\n",
    "print(geodtic1 * geodtic1 + 3 * geodtic1)\n",
    "print(\"geodtic2*geodtic2 + 3*geodtic2\")\n",
    "print(geodtic2 * geodtic2 + 3 * geodtic2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1988993a",
   "metadata": {
    "hideCode": false
   },
   "source": [
    "    ----------- ECEF Coordinate System ----------------\n",
    "\n",
    "    Generic container for Earth-Centered Earth-Fixed (ECEF) coordinate system. Center of Earth is the origin of this frame.\n",
    "\n",
    "\tECEF is a right-handed Cartesian coordinate system with the origin at the Earth’s center. This coordinate frame is fixed with respect to the Earth (i.e., rotates along with the Earth). Units are in meters. The three axis are defined as follows:\n",
    "\tx:\tPasses through the equator at the Prime Meridian (latitude = 0, longitude = 0).\n",
    "\ty:\tPasses through the equator 90 degrees east of the Prime Meridian \n",
    "\t\t(latitude = 0, longitude = 90 degrees).\n",
    "\tz:\tPasses through the North Pole (latitude = 90 degrees, longitude = any value).\n",
    "\n",
    "    This CS is built on top of CartesianRepresentation and has x, y, and z as an input. x, y, and z can be either number or numpy.ndarray. It also takes other known coordinate system as an input and automatically convert it into ECEF CS. It has getter and setter method.\n",
    "\n",
    "    ecef = ECEF(x=0, y=0, z=0)\n",
    "    ecef = ECEF(x=ndarray, y=ndarray, z=ndarray)\n",
    "    ecef = ECEF(geodetic)\n",
    "    ecef = ECEF(grandcs)\n",
    "    \n",
    "    ----Getter\n",
    "        x = ecef.x\n",
    "        y = ecef.y\n",
    "        z = ecef.z\n",
    "\n",
    "    ----Setter\n",
    "        ecef.x = x*x\n",
    "        ecef.y = y*y\n",
    "        ecef.z = z*z\n",
    "\n",
    "    There are two methods to transform from other known coordinate system to ECEF CS.\n",
    "    \n",
    "    1. Instantiating a required CS with a given CS as an input\n",
    "    \n",
    "        ecef1 = ECEF(geodetic) --> changing from Geodetic CS to ECEF CS.\n",
    "        ecef2 = ECEF(grandcs)  --> changing from GRAND CS to ECEF CS.\n",
    "\n",
    "    2. Calling a method from the given CS object.\n",
    "\n",
    "        ecef1 = geodetic.geodetic_to_ecef()\n",
    "        ecef2 = grandcs.grand_to_ecef()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "754cbe2c",
   "metadata": {
    "hideCode": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----3x1 ECEF (x, y, z array input)\n",
      "[[6378139.]\n",
      " [      0.]\n",
      " [      0.]] <class 'grand.geo.coordinates.ECEF'> Initial\n",
      "--getter\n",
      "[6378139.] x <class 'grand.geo.coordinates.ECEF'> getter\n",
      "[0.] y <class 'grand.geo.coordinates.ECEF'> getter\n",
      "[0.] z <class 'grand.geo.coordinates.ECEF'> getter\n",
      "--setter\n",
      "[[6.378149e+06]\n",
      " [1.000000e+01]\n",
      " [1.000000e+01]] <class 'grand.geo.coordinates.ECEF'> setter (added 10) \n",
      "\n",
      "----3x4 ECEF (x, y, z array input)-----\n",
      "[[6378139. 6378139. 6378139. 6378139.]\n",
      " [      0.       0.       0.       0.]\n",
      " [      0.       0.       0.       0.]] <class 'grand.geo.coordinates.ECEF'> Initial\n",
      "--getter\n",
      "[6378139. 6378139. 6378139. 6378139.] x <class 'grand.geo.coordinates.ECEF'> getter\n",
      "[0. 0. 0. 0.] y <class 'grand.geo.coordinates.ECEF'> getter\n",
      "[0. 0. 0. 0.] z <class 'grand.geo.coordinates.ECEF'> getter\n",
      "--setter\n",
      "[[6.378149e+06 6.378149e+06 6.378149e+06 6.378149e+06]\n",
      " [1.000000e+01 1.000000e+01 1.000000e+01 1.000000e+01]\n",
      " [1.000000e+01 1.000000e+01 1.000000e+01 1.000000e+01]] <class 'grand.geo.coordinates.ECEF'> setter (added 10) \n",
      "\n",
      "\n",
      "----ECEF to other cs transformation------\n",
      "\n",
      "----3x1 array\n",
      "[[6378139.]\n",
      " [      0.]\n",
      " [      0.]] <class 'grand.geo.coordinates.ECEF'> Initial\n",
      "--to Geodetic\n",
      "[[  0.        ]\n",
      " [  0.        ]\n",
      " [-15.17734519]] <class 'grand.geo.coordinates.Geodetic'> style 1\n",
      "[[  0.        ]\n",
      " [  0.        ]\n",
      " [-15.17734519]] <class 'grand.geo.coordinates.Geodetic'> style 2\n",
      "--to GRANDCS\n",
      "[[  118397.38092012]\n",
      " [ 6374522.28954042]\n",
      " [-6570656.05991997]] <class 'grand.geo.coordinates.GRANDCS'> style 1\n",
      "[[  118397.38092012]\n",
      " [ 6374522.28954042]\n",
      " [-6570656.05991997]] <class 'grand.geo.coordinates.GRANDCS'> style 2\n",
      "\n",
      "----3x4 array\n",
      "[[6378139. 6378139. 6378139. 6378139.]\n",
      " [      0.       0.       0.       0.]\n",
      " [      0.       0.       0.       0.]] <class 'grand.geo.coordinates.ECEF'> Initial\n",
      "--to Geodetic\n",
      "[[  0.           0.           0.           0.        ]\n",
      " [  0.           0.           0.           0.        ]\n",
      " [-15.17734519 -15.17734519 -15.17734519 -15.17734519]] <class 'grand.geo.coordinates.Geodetic'> style 1\n",
      "[[  0.           0.           0.           0.        ]\n",
      " [  0.           0.           0.           0.        ]\n",
      " [-15.17734519 -15.17734519 -15.17734519 -15.17734519]] <class 'grand.geo.coordinates.Geodetic'> style 2\n",
      "--to GRANDCS\n",
      "[[  118397.38092012   118397.38092012   118397.38092012   118397.38092012]\n",
      " [ 6374522.28954042  6374522.28954042  6374522.28954042  6374522.28954042]\n",
      " [-6570656.05991997 -6570656.05991997 -6570656.05991997 -6570656.05991997]] <class 'grand.geo.coordinates.GRANDCS'> style 1\n",
      "[[  118397.38092012   118397.38092012   118397.38092012   118397.38092012]\n",
      " [ 6374522.28954042  6374522.28954042  6374522.28954042  6374522.28954042]\n",
      " [-6570656.05991997 -6570656.05991997 -6570656.05991997 -6570656.05991997]] <class 'grand.geo.coordinates.GRANDCS'> style 2\n",
      "\n",
      "----Mathematical Operation (shape should be the same)\n",
      "ecef1*ecef1 + 3*ecef1\n",
      "[[4.06806762e+13]\n",
      " [0.00000000e+00]\n",
      " [0.00000000e+00]]\n",
      "ecef2*ecef2 + 3*ecef2\n",
      "[[4.06806762e+13 4.06806762e+13 4.06806762e+13 4.06806762e+13]\n",
      " [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]\n",
      " [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]\n"
     ]
    }
   ],
   "source": [
    "Ex = 6378139 * np.ones(4)  # 2 m above mean sea level. R_earth_eqr = 6378137 m.\n",
    "Ey = np.zeros(4)\n",
    "Ez = np.zeros(4)\n",
    "ka = np.zeros(4)\n",
    "\n",
    "ecef1 = ECEF(x=6378139, y=0, z=0)  # R_earth_eq = 6378137 m\n",
    "ecef2 = ECEF(x=Ex, y=Ey, z=Ez)  # R_earth_eq = 6378137 m\n",
    "\n",
    "print(\"----3x1 ECEF (x, y, z array input)\")\n",
    "print(ecef1, type(ecef1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(ecef1.x, \"x\", type(ecef1.x), \"getter\")\n",
    "print(ecef1.y, \"y\", type(ecef1.y), \"getter\")\n",
    "print(ecef1.z, \"z\", type(ecef1.z), \"getter\")\n",
    "\n",
    "ecef1.x = ecef1.x + 10\n",
    "ecef1.y = ecef1.y + 10\n",
    "ecef1.z = ecef1.z + 10\n",
    "print(\"--setter\")\n",
    "print(ecef1, type(ecef1), \"setter (added 10) \\n\")\n",
    "\n",
    "print(\"----3x4 ECEF (x, y, z array input)-----\")\n",
    "print(ecef2, type(ecef1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(ecef2.x, \"x\", type(ecef2.x), \"getter\")\n",
    "print(ecef2.y, \"y\", type(ecef2.y), \"getter\")\n",
    "print(ecef2.z, \"z\", type(ecef2.z), \"getter\")\n",
    "\n",
    "ecef2.x = ecef2.x + 10\n",
    "ecef2.y = ecef2.y + 10\n",
    "ecef2.z = ecef2.z + 10\n",
    "print(\"--setter\")\n",
    "print(ecef2, type(ecef2), \"setter (added 10) \\n\")\n",
    "\n",
    "ecef1 = ECEF(x=6378139, y=0, z=0)  # R_earth_eq = 6378137 m\n",
    "ecef2 = ECEF(x=Ex, y=Ey, z=Ez)  # R_earth_eq = 6378137 m\n",
    "\n",
    "print(\"\\n----ECEF to other cs transformation------\\n\")\n",
    "etg1a = Geodetic(ecef1)\n",
    "etg1b = ecef1.ecef_to_geodetic()\n",
    "\n",
    "print(\"----3x1 array\")\n",
    "print(ecef1, type(ecef1), \"Initial\")\n",
    "\n",
    "print(\"--to Geodetic\")\n",
    "print(etg1a, type(etg1a), \"style 1\")\n",
    "print(etg1b, type(etg1b), \"style 2\")\n",
    "\n",
    "print(\"--to GRANDCS\")\n",
    "etG1a = GRANDCS(ecef1)\n",
    "etG1b = ecef1.ecef_to_grandcs()\n",
    "print(etG1a, type(etG1a), \"style 1\")\n",
    "print(etG1b, type(etG1b), \"style 2\")\n",
    "\n",
    "etg2a = Geodetic(ecef2)\n",
    "etg2b = ecef2.ecef_to_geodetic()\n",
    "\n",
    "print(\"\\n----3x4 array\")\n",
    "print(ecef2, type(ecef2), \"Initial\")\n",
    "\n",
    "print(\"--to Geodetic\")\n",
    "print(etg2a, type(etg2a), \"style 1\")\n",
    "print(etg2b, type(etg2b), \"style 2\")\n",
    "\n",
    "print(\"--to GRANDCS\")\n",
    "etG2a = GRANDCS(ecef2)\n",
    "etG2b = ecef2.ecef_to_grandcs()\n",
    "print(etG2a, type(etG2a), \"style 1\")\n",
    "print(etG2b, type(etG2b), \"style 2\")\n",
    "\n",
    "print(\"\\n----Mathematical Operation (shape should be the same)\")\n",
    "print(\"ecef1*ecef1 + 3*ecef1\")\n",
    "print(ecef1 * ecef1 + 3 * ecef1)\n",
    "print(\"ecef2*ecef2 + 3*ecef2\")\n",
    "print(ecef2 * ecef2 + 3 * ecef2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bb71e48",
   "metadata": {},
   "source": [
    "    ----------- Local Tangential Plane (LTP) Coordinate System ----------------\n",
    "\n",
    "    Generic container for LTP coordinate system. User defined location is used as the origin of this frame. Orientation of the frame is also defined by user, i.e. 'NWU' or 'ENU'.\n",
    "    \n",
    "\tLTP is a right-handed Cartesian coordinate system with user defined origin and orientation. This coordinate frame is fixed with respect to the Earth (i.e., rotates along with the Earth). Units are in meters.\n",
    "\n",
    "    This CS is built on top of CartesianRepresentation and has x, y, and z as an input. x, y, and z can be either number or numpy.ndarray. It also takes other known coordinate system as an input and automatically convert it into LTP CS. It is a bit tricky to transform from other CS to LTP CS. Location and orientation of the LTP frame must be provided to which the coordinates from other CS will be transformed. It has all features that CartesianRepresentation has, like getter and setter method.\n",
    "    \n",
    "    Default value used:\n",
    "        magnetic = False\n",
    "        magmodel = 'IGRF13'\n",
    "        obstime  = '2020-01-01'\n",
    "    \n",
    "    ltp = LTP(x=0, y=0, z=0, \n",
    "              location    = location,\n",
    "              orientation = orientation,\n",
    "\t\t\t  magnetic    = magnetic, \n",
    "\t\t\t  magmodel    = magmodel,\n",
    "\t\t\t  declination = declination, \n",
    "\t\t\t  obstime     = obstime)\n",
    "    ltp = LTP(x=ndarray, y=ndarray, z=ndarray, \n",
    "              location    = location,\n",
    "              orientation = orientation,\n",
    "\t\t\t  magnetic    = magnetic, \n",
    "\t\t\t  magmodel    = magmodel,\n",
    "\t\t\t  declination = declination, \n",
    "\t\t\t  obstime     = obstime)\n",
    "    \n",
    "    ----Getter\n",
    "        x = ltp.x\n",
    "        y = ltp.y\n",
    "        z = ltp.z\n",
    "\n",
    "    ----Setter\n",
    "        ltp.x = x*x\n",
    "        ltp.y = y*y\n",
    "        ltp.z = z*z\n",
    "\n",
    "    ----attributes\n",
    "        ltp.basis\n",
    "        ltp.location\n",
    "        ltp.orientation\n",
    "        ltp.magnetic\n",
    "        ltp.magmodel\n",
    "        ltp.declination\n",
    "        ltp.obstime\n",
    "        \n",
    "    There are two methods to transform from one LTP CS to another LTP CS and from other known coordinate system to LTP CS.\n",
    "    \n",
    "    1. Instantiating a required CS with a given CS as an input. I personally prefer second option while converting from a given CS to LTP CS.\n",
    "    \n",
    "        ltp4 = LTP(ltpA, \n",
    "                   location    = ltpB.location,\n",
    "\t\t\t\t   orientation = ltpB.orientation,\n",
    "\t\t\t\t   magnetic    = ltpB.magnetic, \n",
    "\t\t\t\t   magmodel    = ltpB.magmodel,\n",
    "\t\t\t\t   declination = ltpB.declination, \n",
    "\t\t\t\t   obstime     = ltpB.obstime)     --> changing from LTP A-frame to LTP B-frame.\n",
    "\n",
    "        ltp1 = LTP(ecef, \n",
    "                   location    = location,\n",
    "\t\t\t\t   orientation = orientation,\n",
    "\t\t\t\t   magnetic    = magnetic, \n",
    "\t\t\t\t   magmodel    = magmodel,\n",
    "\t\t\t\t   declination = declination, \n",
    "\t\t\t\t   obstime     = obstime)          --> changing from ECEF CS to LTP CS.\n",
    "        ltp2 = LTP(geodetic, \n",
    "                   location    = location,\n",
    "\t\t\t\t   orientation = orientation,\n",
    "\t\t\t\t   magnetic    = magnetic, \n",
    "\t\t\t\t   magmodel    = magmodel,\n",
    "\t\t\t\t   declination = declination, \n",
    "\t\t\t\t   obstime     = obstime)          --> changing from Geodetic CS to LTP CS.\n",
    "        ltp3 = LTP(grandcs, \n",
    "                   location    = location,\n",
    "\t\t\t\t   orientation = orientation,\n",
    "\t\t\t\t   magnetic    = magnetic, \n",
    "\t\t\t\t   magmodel    = magmodel,\n",
    "\t\t\t\t   declination = declination, \n",
    "\t\t\t\t   obstime     = obstime)          --> changing from GRAND CS to LTP CS.\n",
    "        \n",
    "    2. Calling a method from the given CS object.\n",
    "       Change from a given coordinate system to a required LTP frame. At first define a LTP frame that you want other coordintes to be transformed.\n",
    "        ltp_frame = LTP(location    = location,\n",
    "                        orientation = orientation,\n",
    "                        magnetic    = magnetic, \n",
    "                        magmodel    = magmodel,\n",
    "                        declination = declination, \n",
    "                        obstime     = obstime)\n",
    "        ltp1 = ecef.ecef_to_ltp(ltp_frame)\n",
    "        ltp2 = geodetic.geodetic_to_ltp(ltp_frame)\n",
    "        ltp3 = grandcs.grand_to_ltp(ltp_frame)\n",
    "        ltp4 = ltpA.ltp_to_ltp(ltp_frame)  # change from A-frame to B-frame.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3ae131aa",
   "metadata": {
    "hideCode": true,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test to check a memory is not shared among LTP attributes. Make sure location1 stays the same and doesnot change to location2. If memory is shared, location1 and location2 becomes the same in the second case.\n",
      "[[2.76666278e-10]\n",
      " [4.51830320e+06]\n",
      " [4.48806073e+06]] location1 <class 'grand.geo.coordinates.ECEF'> \n",
      "\n",
      "[[2.76666278e-10]\n",
      " [4.51830320e+06]\n",
      " [4.48806073e+06]] location1 <class 'grand.geo.coordinates.ECEF'> \n",
      "\n",
      "[[  80214.76849758]\n",
      " [4595501.00944669]\n",
      " [4408791.42538495]] location2 <class 'grand.geo.coordinates.ECEF'> \n",
      "\n",
      "Attributes of LTP coordinate system.\n",
      "-----------------------------------\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]] LTP <class 'grand.geo.coordinates.LTP'>\n",
      "[[2.76666278e-10]\n",
      " [4.51830320e+06]\n",
      " [4.48806073e+06]] location <class 'grand.geo.coordinates.ECEF'>\n",
      "[[-1.00000000e+00  1.79345371e-17  4.32978028e-17]\n",
      " [-4.32978028e-17 -7.07106781e-01  7.07106781e-01]\n",
      " [ 4.32978028e-17  7.07106781e-01  7.07106781e-01]] basis <class 'numpy.ndarray'> \n",
      "\n",
      "orientation: ENU <class 'str'>\n",
      "magnetic   : False <class 'bool'>\n",
      "declination: 0.0 <class 'float'> \n",
      "\n",
      "----3x1 LTP (x, y, z array input)\n",
      "[[0.]\n",
      " [0.]\n",
      " [0.]] <class 'grand.geo.coordinates.LTP'> Initial\n",
      "--getter\n",
      "[0.] x <class 'grand.geo.coordinates.LTP'> getter\n",
      "[0.] y <class 'grand.geo.coordinates.LTP'> getter\n",
      "[0.] z <class 'grand.geo.coordinates.LTP'> getter\n",
      "--setter\n",
      "[[10.]\n",
      " [10.]\n",
      " [10.]] <class 'grand.geo.coordinates.LTP'> setter (added 10) \n",
      "\n",
      "----3x4 LTP (x, y, z array input)-----\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]] <class 'grand.geo.coordinates.LTP'> Initial\n",
      "--getter\n",
      "[0. 0. 0. 0.] x <class 'grand.geo.coordinates.LTP'> getter\n",
      "[0. 0. 0. 0.] y <class 'grand.geo.coordinates.LTP'> getter\n",
      "[0. 0. 0. 0.] z <class 'grand.geo.coordinates.LTP'> getter\n",
      "--setter\n",
      "[[10. 10. 10. 10.]\n",
      " [10. 10. 10. 10.]\n",
      " [10. 10. 10. 10.]] <class 'grand.geo.coordinates.LTP'> setter (added 10) \n",
      "\n",
      "\n",
      "----LTP to other cs transformation------\n",
      "\n",
      "----3x1 array\n",
      "[[0.]\n",
      " [0.]\n",
      " [0.]] <class 'grand.geo.coordinates.LTP'> Initial\n",
      "--to different LTP's location and orientation\n",
      "[[ 78855.26386686]\n",
      " [111611.9833387 ]\n",
      " [ -1464.94513447]] <class 'grand.geo.coordinates.LTP'> style 1\n",
      "[[ 78855.26386686]\n",
      " [111611.9833387 ]\n",
      " [ -1464.94513447]] <class 'grand.geo.coordinates.LTP'> style 2\n",
      "--to Geodetic\n",
      "[[  45.]\n",
      " [  90.]\n",
      " [1000.]] <class 'grand.geo.coordinates.Geodetic'> style 1\n",
      "[[  45.]\n",
      " [  90.]\n",
      " [1000.]] <class 'grand.geo.coordinates.Geodetic'> style 2\n",
      "--to ECEF\n",
      "[[2.76666278e-10]\n",
      " [4.51830320e+06]\n",
      " [4.48806073e+06]] <class 'grand.geo.coordinates.ECEF'> style 1\n",
      "[[2.76666278e-10]\n",
      " [4.51830320e+06]\n",
      " [4.48806073e+06]] <class 'grand.geo.coordinates.ECEF'> style 2\n",
      "\n",
      "----3x4 array\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]] <class 'grand.geo.coordinates.LTP'> Initial\n",
      "--to different LTP's location and orientation\n",
      "ltp4: [[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]]\n",
      "ltp4: [[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]]\n",
      "[[ 78855.26386686  78855.26386686  78855.26386686  78855.26386686]\n",
      " [111611.9833387  111611.9833387  111611.9833387  111611.9833387 ]\n",
      " [ -1464.94513447  -1464.94513447  -1464.94513447  -1464.94513447]] <class 'grand.geo.coordinates.LTP'> style 1\n",
      "[[ 78855.26386686  78855.26386686  78855.26386686  78855.26386686]\n",
      " [111611.9833387  111611.9833387  111611.9833387  111611.9833387 ]\n",
      " [ -1464.94513447  -1464.94513447  -1464.94513447  -1464.94513447]] <class 'grand.geo.coordinates.LTP'> style 2\n",
      "--to Geodetic\n",
      "[[  45.   45.   45.   45.]\n",
      " [  90.   90.   90.   90.]\n",
      " [1000. 1000. 1000. 1000.]] <class 'grand.geo.coordinates.Geodetic'> style 1\n",
      "[[  45.   45.   45.   45.]\n",
      " [  90.   90.   90.   90.]\n",
      " [1000. 1000. 1000. 1000.]] <class 'grand.geo.coordinates.Geodetic'> style 2\n",
      "--to ECEF\n",
      "[[2.76666278e-10 2.76666278e-10 2.76666278e-10 2.76666278e-10]\n",
      " [4.51830320e+06 4.51830320e+06 4.51830320e+06 4.51830320e+06]\n",
      " [4.48806073e+06 4.48806073e+06 4.48806073e+06 4.48806073e+06]] <class 'grand.geo.coordinates.ECEF'> style 1\n",
      "[[2.76666278e-10 2.76666278e-10 2.76666278e-10 2.76666278e-10]\n",
      " [4.51830320e+06 4.51830320e+06 4.51830320e+06 4.51830320e+06]\n",
      " [4.48806073e+06 4.48806073e+06 4.48806073e+06 4.48806073e+06]] <class 'grand.geo.coordinates.ECEF'> style 2\n",
      "\n",
      "----Mathematical Operation (shape should be the same)\n",
      "ltp1*ltp1 + 3*ltp1 + 1\n",
      "[[1.]\n",
      " [1.]\n",
      " [1.]]\n",
      "ltp2*gcs2 + 3*ltp2 + 1\n",
      "[[1. 1. 1. 1.]\n",
      " [1. 1. 1. 1.]\n",
      " [1. 1. 1. 1.]]\n",
      "\n",
      "----Other CS to LTP------\n",
      "\n",
      "--from ECEF\n",
      "[[-6378138.        ]\n",
      " [   21384.65560482]\n",
      " [-6368461.00984963]] <class 'grand.geo.coordinates.LTP'> style1\n",
      "[[-6378138.        ]\n",
      " [   21384.65560482]\n",
      " [-6368461.00984963]] <class 'grand.geo.coordinates.LTP'> style2 \n",
      "\n",
      "--from Geodetic\n",
      "[[-6378154.17734519]\n",
      " [   21384.65560482]\n",
      " [-6368461.00984963]] <class 'grand.geo.coordinates.LTP'> style1\n",
      "[[-6378154.17734519]\n",
      " [   21384.65560482]\n",
      " [-6368461.00984963]] <class 'grand.geo.coordinates.LTP'> style2 \n",
      "\n",
      "--from GRAND\n",
      "[[ 198380.49987406]\n",
      " [-675044.52041141]\n",
      " [ -37074.81976542]] <class 'grand.geo.coordinates.LTP'> style1\n",
      "[[ 198380.49987406]\n",
      " [-675044.52041141]\n",
      " [ -37074.81976542]] <class 'grand.geo.coordinates.LTP'> style2 \n",
      "\n"
     ]
    }
   ],
   "source": [
    "x = np.zeros(4)\n",
    "y = x\n",
    "z = y\n",
    "\n",
    "loc1 = Geodetic(latitude=45, longitude=90, height=1000)\n",
    "loc2 = Geodetic(latitude=44, longitude=89, height=1000)\n",
    "ltp1 = LTP(x=0, y=0, z=0, orientation=\"ENU\", location=loc1)\n",
    "ltp2 = LTP(x=x, y=y, z=z, orientation=\"ENU\", location=loc1)\n",
    "\n",
    "print(\n",
    "    \"Test to check a memory is not shared among LTP attributes. Make sure location1 stays the same and doesnot change to location2. \\\n",
    "If memory is shared, location1 and location2 becomes the same in the second case.\"\n",
    ")\n",
    "\n",
    "print(ltp1.location, \"location1\", type(ltp1.location), \"\\n\")\n",
    "ltp1_ = LTP(ltp1, location=loc2, orientation=\"ENU\")\n",
    "print(ltp1.location, \"location1\", type(ltp1.location), \"\\n\")\n",
    "print(ltp1_.location, \"location2\", type(ltp1_.location), \"\\n\")\n",
    "\n",
    "print(\"Attributes of LTP coordinate system.\")\n",
    "print(\"-----------------------------------\")\n",
    "# print(ltp1.__dict__)\n",
    "print(ltp2, \"LTP\", type(ltp2))\n",
    "print(ltp2.location, \"location\", type(ltp2.location))\n",
    "print(ltp2.basis, \"basis\", type(ltp2.basis), \"\\n\")\n",
    "\n",
    "print(\"orientation:\", ltp2.orientation, type(ltp2.orientation))\n",
    "print(\"magnetic   :\", ltp2.magnetic, type(ltp2.magnetic))\n",
    "print(\"declination:\", ltp2.declination, type(ltp2.declination), \"\\n\")\n",
    "\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "gcs = GRANDCS(x=0, y=0, z=0)\n",
    "print(gcs, 'GRAND', gcs.x, gcs.y, gcs.z, gcs.location, gcs.orientation)\n",
    "ecef = ECEF(gcs)\n",
    "geod = Geodetic(gcs)\n",
    "print(ecef, 'ECEF', type(ecef))\n",
    "print(geod, 'GEOD', type(geod))\n",
    "ltp2 = LTP(gcs, location=loc1, orientation='NWU')\n",
    "\n",
    "\n",
    "print(ltp1.location.base, ltp1_.location.base, ltp1_0.location.base, )\n",
    "print('main:', id(ltp1), id(ltp1_0), id(ltp2))\n",
    "print('loca:', id(ltp1.location), id(ltp1_0.location), id(ltp2.location))\n",
    "print('decl:', id(ltp1.declination), id(ltp1_0.declination), id(ltp2.declination), '\\n')\n",
    "\"\"\"\n",
    "\n",
    "print(\"----3x1 LTP (x, y, z array input)\")\n",
    "print(ltp1, type(ltp1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(ltp1.x, \"x\", type(ltp1.x), \"getter\")\n",
    "print(ltp1.y, \"y\", type(ltp1.y), \"getter\")\n",
    "print(ltp1.z, \"z\", type(ltp1.z), \"getter\")\n",
    "\n",
    "ltp1.x = ltp1.x + 10\n",
    "ltp1.y = ltp1.y + 10\n",
    "ltp1.z = ltp1.z + 10\n",
    "print(\"--setter\")\n",
    "print(ltp1, type(ltp1), \"setter (added 10) \\n\")\n",
    "\n",
    "print(\"----3x4 LTP (x, y, z array input)-----\")\n",
    "print(ltp2, type(ltp1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(ltp2.x, \"x\", type(ltp2.x), \"getter\")\n",
    "print(ltp2.y, \"y\", type(ltp2.y), \"getter\")\n",
    "print(ltp2.z, \"z\", type(ltp2.z), \"getter\")\n",
    "\n",
    "ltp2.x = ltp2.x + 10\n",
    "ltp2.y = ltp2.y + 10\n",
    "ltp2.z = ltp2.z + 10\n",
    "print(\"--setter\")\n",
    "print(ltp2, type(ltp2), \"setter (added 10) \\n\")\n",
    "\n",
    "\n",
    "print(\"\\n----LTP to other cs transformation------\\n\")\n",
    "\n",
    "ltp1 = LTP(x=0, y=0, z=0, orientation=\"ENU\", location=loc1)\n",
    "ltp2 = LTP(x=x, y=y, z=z, orientation=\"ENU\", location=loc1)\n",
    "\n",
    "print(\"----3x1 array\")\n",
    "print(ltp1, type(ltp1), \"Initial\")\n",
    "\n",
    "print(\"--to different LTP's location and orientation\")\n",
    "# transform ltp1 w.r.t ltp3's location and orientation.\n",
    "ltp3 = LTP(x=0, y=0, z=0, orientation=\"ENU\", location=loc2)  # different location\n",
    "LtL1a = LTP(\n",
    "    ltp1,\n",
    "    orientation=ltp3.orientation,\n",
    "    location=ltp3.location,\n",
    "    magnetic=ltp3.magnetic,\n",
    "    magmodel=ltp3.magmodel,\n",
    "    declination=ltp3.declination,\n",
    "    obstime=ltp3.obstime,\n",
    ")\n",
    "LtL1b = ltp1.ltp_to_ltp(ltp3)  # Note: I personally prefer this.\n",
    "print(LtL1a, type(LtL1a), \"style 1\")\n",
    "print(LtL1b, type(LtL1b), \"style 2\")\n",
    "\n",
    "print(\"--to Geodetic\")\n",
    "Ltg1a = Geodetic(ltp1)\n",
    "Ltg1b = ltp1.ltp_to_geodetic()\n",
    "print(Ltg1a, type(Ltg1a), \"style 1\")\n",
    "print(Ltg1b, type(Ltg1b), \"style 2\")\n",
    "\n",
    "print(\"--to ECEF\")\n",
    "Lte1a = ECEF(ltp1)\n",
    "Lte1b = ltp1.ltp_to_ecef()\n",
    "print(Lte1a, type(Lte1a), \"style 1\")\n",
    "print(Lte1b, type(Lte1b), \"style 2\")\n",
    "\n",
    "\n",
    "print(\"\\n----3x4 array\")\n",
    "print(ltp2, type(ltp2), \"Initial\")\n",
    "\n",
    "print(\"--to different LTP's location and orientation\")\n",
    "# transform ltp2 w.r.t ltp4's location and orientation.\n",
    "ltp4 = LTP(x=x, y=x, z=x, orientation=\"ENU\", location=loc2)  # different location\n",
    "print(\"ltp4:\", ltp4)\n",
    "LtL2a = LTP(\n",
    "    ltp2,\n",
    "    orientation=ltp4.orientation,\n",
    "    location=ltp4.location,\n",
    "    magnetic=ltp4.magnetic,\n",
    "    magmodel=ltp4.magmodel,\n",
    "    declination=ltp4.declination,\n",
    "    obstime=ltp4.obstime,\n",
    ")\n",
    "LtL2b = ltp2.ltp_to_ltp(ltp4)  # Note: I personally prefer this.\n",
    "print(\"ltp4:\", ltp4)\n",
    "print(LtL2a, type(LtL2a), \"style 1\")\n",
    "print(LtL2b, type(LtL2b), \"style 2\")\n",
    "\n",
    "print(\"--to Geodetic\")\n",
    "Ltg2a = Geodetic(ltp2)\n",
    "Ltg2b = ltp2.ltp_to_geodetic()\n",
    "print(Ltg2a, type(Ltg2a), \"style 1\")\n",
    "print(Ltg2b, type(Ltg2b), \"style 2\")\n",
    "\n",
    "print(\"--to ECEF\")\n",
    "Lte2a = ECEF(ltp2)\n",
    "Lte2b = ltp2.ltp_to_ecef()\n",
    "print(Lte2a, type(Lte2a), \"style 1\")\n",
    "print(Lte2b, type(Lte2b), \"style 2\")\n",
    "\n",
    "print(\"\\n----Mathematical Operation (shape should be the same)\")\n",
    "print(\"ltp1*ltp1 + 3*ltp1 + 1\")\n",
    "print(ltp1 * ltp1 + 3 * ltp1 + 1)\n",
    "print(\"ltp2*gcs2 + 3*ltp2 + 1\")\n",
    "print(ltp2 * ltp2 + 3 * ltp2 + 1)\n",
    "\n",
    "print(\"\\n----Other CS to LTP------\\n\")\n",
    "ltp_frame = LTP(orientation=\"ENU\", location=loc1)\n",
    "\n",
    "ecef = ECEF(x=6378138.0, y=0, z=0)\n",
    "geodetic = Geodetic(latitude=0, longitude=0, height=0)\n",
    "gcs = GRANDCS(x=0, y=0, z=0)\n",
    "\n",
    "etL1a = LTP(\n",
    "    ecef,\n",
    "    orientation=ltp_frame.orientation,\n",
    "    location=ltp_frame.location,\n",
    "    magnetic=ltp_frame.magnetic,\n",
    "    magmodel=ltp_frame.magmodel,\n",
    "    declination=ltp_frame.declination,\n",
    "    obstime=ltp_frame.obstime,\n",
    ")\n",
    "\n",
    "gtL1a = LTP(\n",
    "    geodetic,\n",
    "    orientation=ltp_frame.orientation,\n",
    "    location=ltp_frame.location,\n",
    "    magnetic=ltp_frame.magnetic,\n",
    "    magmodel=ltp_frame.magmodel,\n",
    "    declination=ltp_frame.declination,\n",
    "    obstime=ltp_frame.obstime,\n",
    ")\n",
    "GtL1a = LTP(\n",
    "    gcs,\n",
    "    orientation=ltp_frame.orientation,\n",
    "    location=ltp_frame.location,\n",
    "    magnetic=ltp_frame.magnetic,\n",
    "    magmodel=ltp_frame.magmodel,\n",
    "    declination=ltp_frame.declination,\n",
    "    obstime=ltp_frame.obstime,\n",
    ")\n",
    "\n",
    "# I prefer this style\n",
    "etL1b = ecef.ecef_to_ltp(ltp_frame)\n",
    "gtL1b = geodetic.geodetic_to_ltp(ltp_frame)\n",
    "GtL1b = gcs.grandcs_to_ltp(ltp_frame)\n",
    "\n",
    "print(\"--from ECEF\")\n",
    "print(etL1a, type(etL1a), \"style1\")\n",
    "print(etL1b, type(etL1b), \"style2\", \"\\n\")\n",
    "print(\"--from Geodetic\")\n",
    "print(gtL1a, type(gtL1a), \"style1\")\n",
    "print(gtL1b, type(gtL1b), \"style2\", \"\\n\")\n",
    "print(\"--from GRAND\")\n",
    "print(GtL1a, type(GtL1a), \"style1\")\n",
    "print(GtL1b, type(GtL1b), \"style2\", \"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79021dac",
   "metadata": {},
   "source": [
    "    ----------- GRAND Coordinate System ----------------\n",
    "    \n",
    "    Class for the GRAND coordinate system (cs). This class instantiate coordinates in GRAND's coordinate frame. GRAND CS is built on top of CartesianRepresentation and has x, y, and z as an input. X-axis points toward local geomagnetic North, y-axis is 90 degree West of geomagnetic North, and z-axis is upward (NWU). Input x, y, z can be either in GRAND's CS or in instance of ECEF or Geodetic CS.  x, y, and z can be either number or numpy.ndarray. GRAND CS also has getter and setter method.\n",
    "\n",
    "    grandcs = GRAND(x=0, y=0, z=0)\n",
    "    grandcs = GRAND(x=ndarray, y=ndarray, z=ndarray)\n",
    "    grandcs = GRAND(geodetic)\n",
    "    grandcs = GRAND(ecef)\n",
    "    \n",
    "    ----Getter\n",
    "        x = grandcs.x\n",
    "        y = grandcs.y\n",
    "        z = grandcs.z\n",
    "\n",
    "    ----Setter\n",
    "        grandcs.x = x*x\n",
    "        grandcs.y = y*y\n",
    "        grandcs.z = z*z\n",
    "\n",
    "    There are two methods to transform from other known coordinate system to ECEF CS.\n",
    "    \n",
    "    1. Instantiating a required CS with a given CS as an input\n",
    "    \n",
    "        grandcs1 = GRAND(geodetic) --> changing from Geodetic CS to GRAND CS.\n",
    "        grandcs2 = GRAND(ecef)     --> changing from ECEF CS to GRAND CS.\n",
    "\n",
    "    2. Calling a method from the given CS object.\n",
    "\n",
    "        grandcs1 = geodetic.geodetic_to_grand()\n",
    "        grandcs2 = ecef.ecef_to_grand()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "e3eb60e2",
   "metadata": {
    "hideCode": true,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----3x1 GRAND (x, y, z array input)\n",
      "[[0.]\n",
      " [0.]\n",
      " [0.]] <class 'grand.geo.coordinates.GRANDCS'> Initial \n",
      "\n",
      "Attributes of GRAND coordinate system.\n",
      "-----------------------------------\n",
      "[[-198380.49987406]\n",
      " [4969415.90229663]\n",
      " [3984516.31634217]] location <class 'grand.geo.coordinates.ECEF'>\n",
      "[[ 0.01528752 -0.62766654  0.7783322 ]\n",
      " [ 0.99940098  0.03376326  0.00759792]\n",
      " [-0.03104799  0.77774981  0.62780671]] basis <class 'numpy.ndarray'> \n",
      "\n",
      "orientation   : NWU <class 'str'>\n",
      "magnetic      : True <class 'bool'>\n",
      "magnetic model: IGRF13 <class 'str'>\n",
      "declination   : 0.5592921082062077 <class 'numpy.float64'>\n",
      "obstime       : 2020-01-01 <class 'numpy.float64'> \n",
      "\n",
      "--getter\n",
      "[0.] x <class 'grand.geo.coordinates.GRANDCS'> getter\n",
      "[0.] y <class 'grand.geo.coordinates.GRANDCS'> getter\n",
      "[0.] z <class 'grand.geo.coordinates.GRANDCS'> getter\n",
      "--setter\n",
      "[[10.]\n",
      " [10.]\n",
      " [10.]] <class 'grand.geo.coordinates.GRANDCS'> setter (added 10) \n",
      "\n",
      "----3x4 GRAND (x, y, z array input)-----\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]] <class 'grand.geo.coordinates.GRANDCS'> Initial\n",
      "--getter\n",
      "[0. 0. 0. 0.] x <class 'grand.geo.coordinates.GRANDCS'> getter\n",
      "[0. 0. 0. 0.] y <class 'grand.geo.coordinates.GRANDCS'> getter\n",
      "[0. 0. 0. 0.] z <class 'grand.geo.coordinates.GRANDCS'> getter\n",
      "--setter\n",
      "[[10. 10. 10. 10.]\n",
      " [10. 10. 10. 10.]\n",
      " [10. 10. 10. 10.]] <class 'grand.geo.coordinates.GRANDCS'> setter (added 10) \n",
      "\n",
      "\n",
      "----GRAND to other cs transformation------\n",
      "\n",
      "----3x1 array\n",
      "[[0.]\n",
      " [0.]\n",
      " [0.]] <class 'grand.geo.coordinates.GRANDCS'> Initial\n",
      "--to Geodetic\n",
      "[[  38.88849]\n",
      " [  92.28605]\n",
      " [2920.522  ]] <class 'grand.geo.coordinates.Geodetic'> style 1\n",
      "[[  38.88849]\n",
      " [  92.28605]\n",
      " [2920.522  ]] <class 'grand.geo.coordinates.Geodetic'> style 2\n",
      "--to ECEF\n",
      "[[-198380.49987406]\n",
      " [4969415.90229663]\n",
      " [3984516.31634217]] <class 'grand.geo.coordinates.ECEF'> style 1\n",
      "[[-198380.49987406]\n",
      " [4969415.90229663]\n",
      " [3984516.31634217]] <class 'grand.geo.coordinates.ECEF'> style 2\n",
      "\n",
      "----3x4 array\n",
      "[[0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]\n",
      " [0. 0. 0. 0.]] <class 'grand.geo.coordinates.GRANDCS'> Initial\n",
      "--to Geodetic\n",
      "[[  38.88849   38.88849   38.88849   38.88849]\n",
      " [  92.28605   92.28605   92.28605   92.28605]\n",
      " [2920.522   2920.522   2920.522   2920.522  ]] <class 'grand.geo.coordinates.Geodetic'> style 1\n",
      "[[  38.88849   38.88849   38.88849   38.88849]\n",
      " [  92.28605   92.28605   92.28605   92.28605]\n",
      " [2920.522   2920.522   2920.522   2920.522  ]] <class 'grand.geo.coordinates.Geodetic'> style 2\n",
      "--to ECEF\n",
      "[[-198380.49987406 -198380.49987406 -198380.49987406 -198380.49987406]\n",
      " [4969415.90229663 4969415.90229663 4969415.90229663 4969415.90229663]\n",
      " [3984516.31634217 3984516.31634217 3984516.31634217 3984516.31634217]] <class 'grand.geo.coordinates.ECEF'> style 1\n",
      "[[-198380.49987406 -198380.49987406 -198380.49987406 -198380.49987406]\n",
      " [4969415.90229663 4969415.90229663 4969415.90229663 4969415.90229663]\n",
      " [3984516.31634217 3984516.31634217 3984516.31634217 3984516.31634217]] <class 'grand.geo.coordinates.ECEF'> style 2\n",
      "\n",
      "----Mathematical Operation (shape should be the same)\n",
      "gcs1*gcs1 + 3*gcs1 + 1\n",
      "[[1.]\n",
      " [1.]\n",
      " [1.]]\n",
      "gcs2*gcs2 + 3*gcs2 + 1\n",
      "[[1. 1. 1. 1.]\n",
      " [1. 1. 1. 1.]\n",
      " [1. 1. 1. 1.]]\n"
     ]
    }
   ],
   "source": [
    "x = np.zeros(4)\n",
    "y = x\n",
    "z = y\n",
    "\n",
    "gcs1 = GRANDCS(x=0, y=0, z=0)\n",
    "gcs2 = GRANDCS(x=x, y=y, z=z)\n",
    "\n",
    "print(\"----3x1 GRAND (x, y, z array input)\")\n",
    "print(gcs1, type(gcs1), \"Initial\", \"\\n\")\n",
    "\n",
    "print(\"Attributes of GRAND coordinate system.\")\n",
    "print(\"-----------------------------------\")\n",
    "# print(ltp1.__dict__)\n",
    "print(gcs1.location, \"location\", type(gcs1.location))\n",
    "print(gcs1.basis, \"basis\", type(gcs1.basis), \"\\n\")\n",
    "\n",
    "print(\"orientation   :\", gcs1.orientation, type(gcs1.orientation))\n",
    "print(\"magnetic      :\", gcs1.magnetic, type(gcs1.magnetic))\n",
    "print(\"magnetic model:\", gcs1.magmodel, type(gcs1.magmodel))\n",
    "print(\"declination   :\", gcs1.declination, type(gcs1.declination))\n",
    "print(\"obstime       :\", gcs1.obstime, type(gcs1.declination), \"\\n\")\n",
    "\n",
    "\n",
    "print(\"--getter\")\n",
    "print(gcs1.x, \"x\", type(gcs1.x), \"getter\")\n",
    "print(gcs1.y, \"y\", type(gcs1.y), \"getter\")\n",
    "print(gcs1.z, \"z\", type(gcs1.z), \"getter\")\n",
    "\n",
    "gcs1.x = gcs1.x + 10\n",
    "gcs1.y = gcs1.y + 10\n",
    "gcs1.z = gcs1.z + 10\n",
    "print(\"--setter\")\n",
    "print(gcs1, type(gcs1), \"setter (added 10) \\n\")\n",
    "\n",
    "print(\"----3x4 GRAND (x, y, z array input)-----\")\n",
    "print(gcs2, type(gcs1), \"Initial\")\n",
    "\n",
    "print(\"--getter\")\n",
    "print(gcs2.x, \"x\", type(gcs2.x), \"getter\")\n",
    "print(gcs2.y, \"y\", type(gcs2.y), \"getter\")\n",
    "print(gcs2.z, \"z\", type(gcs2.z), \"getter\")\n",
    "\n",
    "gcs2.x = gcs2.x + 10\n",
    "gcs2.y = gcs2.y + 10\n",
    "gcs2.z = gcs2.z + 10\n",
    "print(\"--setter\")\n",
    "print(gcs2, type(gcs2), \"setter (added 10) \\n\")\n",
    "\n",
    "\n",
    "print(\"\\n----GRAND to other cs transformation------\\n\")\n",
    "\n",
    "gcs1 = GRANDCS(x=0, y=0, z=0)\n",
    "gcs2 = GRANDCS(x=x, y=y, z=z)\n",
    "\n",
    "print(\"----3x1 array\")\n",
    "print(gcs1, type(gcs1), \"Initial\")\n",
    "\n",
    "print(\"--to Geodetic\")\n",
    "Gtg1a = Geodetic(gcs1)\n",
    "Gtg1b = gcs1.grandcs_to_geodetic()\n",
    "print(Gtg1a, type(Gtg1a), \"style 1\")\n",
    "print(Gtg1b, type(Gtg1b), \"style 2\")\n",
    "\n",
    "print(\"--to ECEF\")\n",
    "Gte1a = ECEF(gcs1)\n",
    "Gte1b = gcs1.grandcs_to_ecef()\n",
    "print(Gte1a, type(Gte1a), \"style 1\")\n",
    "print(Gte1b, type(Gte1b), \"style 2\")\n",
    "\n",
    "\n",
    "print(\"\\n----3x4 array\")\n",
    "print(gcs2, type(gcs2), \"Initial\")\n",
    "\n",
    "print(\"--to Geodetic\")\n",
    "Gtg2a = Geodetic(gcs2)\n",
    "Gtg2b = gcs2.grandcs_to_geodetic()\n",
    "print(Gtg2a, type(Gtg2a), \"style 1\")\n",
    "print(Gtg2b, type(Gtg2b), \"style 2\")\n",
    "\n",
    "print(\"--to ECEF\")\n",
    "Gte2a = ECEF(gcs2)\n",
    "Gte2b = gcs2.grandcs_to_ecef()\n",
    "print(Gte2a, type(Gte2a), \"style 1\")\n",
    "print(Gte2b, type(Gte2b), \"style 2\")\n",
    "\n",
    "print(\"\\n----Mathematical Operation (shape should be the same)\")\n",
    "print(\"gcs1*gcs1 + 3*gcs1 + 1\")\n",
    "print(gcs1 * gcs1 + 3 * gcs1 + 1)\n",
    "print(\"gcs2*gcs2 + 3*gcs2 + 1\")\n",
    "print(gcs2 * gcs2 + 3 * gcs2 + 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e13d0b8",
   "metadata": {},
   "source": [
    "    Change possible GP300 antennae positions from Geodetic CS to GRAND CS and plot them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "f92578a3",
   "metadata": {
    "hideCode": true,
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x864 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from grand import grand_get_path_root_pkg\n",
    "\n",
    "layout = grand_get_path_root_pkg() + \"/examples/geo/trial_GP300_layout_2021.txt\"\n",
    "geometry_file = np.loadtxt(layout)\n",
    "longitude = geometry_file[:, 0]\n",
    "latitude = geometry_file[:, 1]\n",
    "altitude = geometry_file[:, 2]\n",
    "\n",
    "grand_origin = Geodetic(\n",
    "    latitude=np.mean(latitude), longitude=np.mean(longitude), height=np.mean(altitude)\n",
    ")\n",
    "\n",
    "# Conversion from Geodetic to GRAND coordinate system.\n",
    "geod = Geodetic(latitude=latitude, longitude=longitude, height=altitude)\n",
    "gcs = GRANDCS(geod, obstime=\"2021-08-25\", location=grand_origin)\n",
    "\n",
    "# ----Plot position of antannae in GRAND coordinate system----\n",
    "x = (gcs.x) / 1000.0  # m -> km\n",
    "y = (gcs.y) / 1000.0  # m -> km\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(x, y, \"ko\", alpha=0.9)\n",
    "plt.xlim(-8, 8)\n",
    "plt.ylim(-18, 18)\n",
    "plt.gca().set_aspect(\"equal\")\n",
    "plt.title(\"GP300 Antennae Position in GRAND CS\")\n",
    "plt.xlabel(\"North [km]\")\n",
    "plt.ylabel(\"West [km]\")\n",
    "plt.grid(ls=\"--\", alpha=0.3)\n",
    "# plt.savefig('GP300_layout_GRANDCS.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d91cc34",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "celltoolbar": "Hide code",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
